package com.trungsi.profile;

import java.io.PrintWriter;

public class Call {
	private final String name;
	
	private long startTime;
	private long endTime;
	
	private long globalStart;
	private long globalEnd;
	
	private final Call parent;
	private Call previous;
	
	private Call lastChild;
	
	public Call(Call parent, String name) {
		this.parent = parent;
		this.name = name;
		if (parent != null)
			parent.addChild(this);
	}

	public long time() {
		return endTime - startTime;
	}
	
	public long realTime() {
		if (lastChild == null) {
			return time();
		} else {
			long time = 0;
			Call child = lastChild;
			while (child != null) {
				time += child.realTime();
				child = child.previous;
			}
			
			return time;
		}
	}
	
	public long globalTime() {
		return globalEnd - globalStart;
	}
	
	public long overhead() {
		return globalTime() - time();
	}
	
	public long bOverhead() {
		return startTime - globalStart;
	}
	
	public long aOverhead() {
		return globalEnd - endTime;
	}
	
	public long globalOverhead() {
		if (lastChild == null) {
			return overhead();
		} else {
			long time = 0;
			Call child = lastChild;
			while (child != null) {
				time += child.globalOverhead();
				child = child.previous;
			}
			
			return time;
		}
	}
	private void addChild(Call call) {
		call.previous = lastChild;
		lastChild = call;
	}
	
	public void print(PrintWriter printer) {
		StringBuilder builder = new StringBuilder();
		print(this, builder, 1);
		
		
		printer.println(builder);
		printer.flush();
	}
	
	private void print(Call call, StringBuilder builder, int level) {
		if (call.globalTime() > 0) { // ignore 0 time
			Call child = call.lastChild;
			while (child != null) {
				print(child, builder, level+1);
				child = child.previous;
			}
			
			builder.append(indent(level) + call.name + 
					", r=" + call.realTime() + 
					", u=" + call.time() + 
					", g=" + call.globalTime() + 
					", bo=" +call.bOverhead() +
					", ao=" +call.aOverhead() +
					", go=" + call.globalOverhead() + '\n');
		}
	}

	private String indent(int deep) {
		StringBuilder builder = new StringBuilder();
		for (int i = 1; i <= deep; i++) {
			builder.append(' ');
		}
		
		return builder.toString();
	}

    public void setGlobalStart(long globalStart) {
        this.globalStart = globalStart;
    }

    public void setStartTime(long time) {
        this.startTime = time;
    }

    public void setEndTime(long endTime) {
        this.endTime = endTime;
    }

    public Call getParent() {
        return parent;
    }

    public long getEndTime() {
        return endTime;
    }

    public long getGlobalStart() {
        return globalStart;
    }

    public void setGlobalEnd(long time) {
        this.globalEnd = time;
    }

    public void remove() {
        parent.lastChild = previous;
    }
}